<template>
    <div class="ganzhi-relations">
      <!-- 顶部连接线区域（可滚动） -->
      <div 
        v-if="tianganRelations.length > 0"
        class="relation-lines-top"
        ref="topLinesRef"
        @scroll="handleTopScroll"
        @touchstart="handleTopTouchStart"
        @touchmove="handleTopTouchMove"
      >
        <!-- 引导图层 -->
        <div 
          v-if="showTopGuide"
          class="scroll-guide"
          :class="{ 'scroll-guide-hiding': topGuideHiding }"
          @click="hideTopGuide"
        >
          <div class="scroll-guide-content">
            <div class="scroll-guide-icon">
              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M12 5L8 9L12 13L16 9L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                <path d="M12 11L8 15L12 19L16 15L12 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </div>
            <div class="scroll-guide-text">上下滑动查看更多</div>
          </div>
        </div>
        <div 
          class="relation-grid-top" 
          :style="{ 
            '--pillar-count': pillars.length,
            '--font-size': `${fontSize}px`,
            '--header-font-size': `${headerFontSize}px`
          }"
        >
          <template v-for="(rel, relIndex) in tianganRelations" :key="`tiangan-${relIndex}`">
            <div 
              v-for="(pillar, colIndex) in pillars" 
              :key="`tiangan-${relIndex}-${colIndex}`"
              class="relation-cell"
            >
              <div 
                v-if="isLineStart(rel, colIndex)"
                class="relation-char-badge relation-char-start"
              >
                {{ getTianganStartChar(rel) }}
              </div>
              <div 
                v-if="isLineEnd(rel, colIndex)"
                class="relation-char-badge relation-char-end"
              >
                {{ getTianganEndChar(rel) }}
              </div>
              <div 
                v-if="getTianganRelationLineStart(rel, colIndex)"
                class="relation-line-container"
                :style="getTianganLineStyle(rel, colIndex)"
              >
                <div class="relation-line-horizontal"></div>
                <span class="relation-label-on-line label-above">{{ getRelationDisplayText(rel) }}</span>
              </div>
            </div>
          </template>
        </div>
      </div>

      <!-- 中间内容区域（固定，不滚动） -->
      <div 
        class="relation-content-fixed"
        ref="gridRef" 
        :style="{ 
          '--pillar-count': pillars.length,
          '--font-size': `${fontSize}px`,
          '--header-font-size': `${headerFontSize}px`
        }"
      >
        <!-- 表头：柱名称 -->
        <div 
          v-for="(pillar, index) in pillars" 
          :key="`header-${index}`"
          class="grid-header"
        >
          {{ pillar.label || `柱${index + 1}` }}
        </div>
  
        <!-- 天干数据 -->
        <div 
          v-for="(pillar, index) in pillars" 
          :key="`gan-${index}`"
          class="data-cell gan-cell"
          :style="{ color: getTianganColor(pillar.gan) }"
        >
          {{ pillar.gan }}
        </div>
  
        <!-- 地支数据 -->
        <div 
          v-for="(pillar, index) in pillars" 
          :key="`zhi-${index}`"
          class="data-cell zhi-cell"
          :style="{ color: getDizhiColor(pillar.zhi) }"
        >
          {{ pillar.zhi }}
        </div>
  
        <!-- 整柱关系（盖头、截脚）显示在地支下面 -->
        <template v-if="singlePillarRelations.length > 0">
          <div 
            v-for="(pillar, index) in pillars" 
            :key="`pillar-single-${index}`"
            class="pillar-single-cell"
          >
            <template v-for="rel in getSinglePillarRelations(index)" :key="rel.type">
              <span class="pillar-single-tag">{{ rel.type }}</span>
            </template>
          </div>
        </template>
      </div>

      <!-- 底部连接线区域（可滚动） -->
      <div 
        v-if="dizhiRelations.length > 0"
        class="relation-lines-bottom"
        ref="bottomLinesRef"
        @scroll="handleBottomScroll"
        @touchstart="handleBottomTouchStart"
        @touchmove="handleBottomTouchMove"
      >
        <!-- 引导图层 -->
        <div 
          v-if="showBottomGuide"
          class="scroll-guide"
          :class="{ 'scroll-guide-hiding': bottomGuideHiding }"
          @click="hideBottomGuide"
        >
          <div class="scroll-guide-content">
            <div class="scroll-guide-icon">
              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path d="M12 5L8 9L12 13L16 9L12 5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                <path d="M12 11L8 15L12 19L16 15L12 11" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
              </svg>
            </div>
            <div class="scroll-guide-text">上下滑动查看更多</div>
          </div>
        </div>
        <div 
          class="relation-grid-bottom" 
          :style="{ 
            '--pillar-count': pillars.length,
            '--font-size': `${fontSize}px`,
            '--header-font-size': `${headerFontSize}px`
          }"
        >
          <template v-for="(rel, relIndex) in dizhiRelations" :key="`dizhi-${relIndex}`">
            <div 
              v-for="(pillar, colIndex) in pillars" 
              :key="`dizhi-${relIndex}-${colIndex}`"
              class="relation-cell"
            >
              <div 
                v-if="isLineStart(rel, colIndex)"
                class="relation-char-badge relation-char-start"
              >
                {{ getDizhiStartChar(rel) }}
              </div>
              <div 
                v-if="isLineEnd(rel, colIndex)"
                class="relation-char-badge relation-char-end"
              >
                {{ getDizhiEndChar(rel) }}
              </div>
              <div 
                v-if="getDizhiRelationLineStart(rel, colIndex)"
                class="relation-line-container"
                :style="getDizhiLineStyle(rel, colIndex)"
              >
                <div class="relation-line-horizontal"></div>
                <span class="relation-label-on-line label-above">{{ getRelationDisplayText(rel) }}</span>
              </div>
            </div>
          </template>
        </div>
      </div>
  
      <!-- 无关系提示 -->
      <div 
        v-if="tianganRelations.length === 0 && dizhiRelations.length === 0 && pillarRelations.length === 0" 
        class="no-relations"
      >
        暂无特殊关系
      </div>
    </div>
  </template>
  
  <script setup lang="ts">
  import { computed, ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'
  import { 
    isTianganChong, 
    isTianganKe, 
    isTianganHe,
    isDizhiLiuhe,
    isDizhiSanhe,
    isDizhiSanhui,
    isDizhiAnhe,
    isDizhiXing,
    isDizhiChong,
    isDizhiPo,
    isDizhiHai,
    isGaitou,
    isJiejiao,
    getTianganHehua,
    getDizhiLiuheHuahua,
    getDizhiSanheHuahua,
    getDizhiSanhuiHuahua,
    isDizhiBanhe,
    isDizhiGongSanhui,
    isDizhiAnheJu,
    isDizhiGonghe,
    isDizhiAnSanhui,
    isDizhiSiheTu
  } from '@/utils/ganzhi-relations'
  import { getTianganColor, getDizhiColor, GANZHI_WUXING } from '@/utils/wuxing'
  
  interface Pillar {
    gan: string
    zhi: string
    label?: string
  }
  
  interface Props {
    pillars: Pillar[]
  }
  
  const props = defineProps<Props>()
  
  interface Relation {
    pair: string
    type: string
    positions?: number[]
  }
  
  // 获取完整的关系显示文本（包含合化信息）
  const getRelationDisplayText = (rel: Relation): string => {
    // 处理相克的情况（如"甲克乙"）
    if (rel.type.includes('克')) {
      return '克'
    }
    
    // 天干五合 - 显示合化信息
    if (rel.type === '五合' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const gan1 = props.pillars[pos1]?.gan
        const gan2 = props.pillars[pos2]?.gan
        if (gan1 && gan2) {
          const huahua = getTianganHehua(gan1, gan2)
          if (huahua) {
            return `合化${huahua}`
          }
        }
      }
      return '合'
    }
    
    // 地支六合 - 显示合化信息
    if (rel.type === '六合' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        if (zhi1 && zhi2) {
          const huahua = getDizhiLiuheHuahua(zhi1, zhi2)
          if (huahua) {
            return `合化${huahua}`
          }
        }
      }
      return '合'
    }
    
    // 地支三合 - 显示三合+化气
    if (rel.type === '三合' && rel.positions && rel.positions.length === 3) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      const pos3 = rel.positions[2]
      if (pos1 !== undefined && pos2 !== undefined && pos3 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        const zhi3 = props.pillars[pos3]?.zhi
        if (zhi1 && zhi2 && zhi3) {
          const huahua = getDizhiSanheHuahua(zhi1, zhi2, zhi3)
          if (huahua) {
            return `三合${huahua}局`
          }
        }
      }
      return '三合'
    }
    
    // 地支半合 - 显示半合+化气
    if (rel.type === '半合' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        if (zhi1 && zhi2) {
          const banhe = isDizhiBanhe(zhi1, zhi2)
          if (banhe.isBanhe && banhe.huahua) {
            return `半合${banhe.huahua}局`
          }
        }
      }
      return '半合'
    }
    
    // 地支三会 - 显示三会+化气
    if (rel.type === '三会' && rel.positions && rel.positions.length === 3) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      const pos3 = rel.positions[2]
      if (pos1 !== undefined && pos2 !== undefined && pos3 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        const zhi3 = props.pillars[pos3]?.zhi
        if (zhi1 && zhi2 && zhi3) {
          const huahua = getDizhiSanhuiHuahua(zhi1, zhi2, zhi3)
          if (huahua) {
            return `三会${huahua}局`
          }
        }
      }
      return '三会'
    }
    
    // 四地支合土局（丑_辰_未_戌合土局）
    if (rel.type === '四合土局' && rel.positions && rel.positions.length === 4) {
      return '四合土局'
    }
    
    // 地支拱合局（拱三合）- 显示拱合+化气局
    if (rel.type === '拱合' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        if (zhi1 && zhi2) {
          const gonghe = isDizhiGonghe(zhi1, zhi2)
          if (gonghe.isGonghe && gonghe.huahua) {
            return `拱合${gonghe.huahua}局`
          }
        }
      }
      return '拱合'
    }
    
    // 地支拱三会 - 显示拱三会+化气局
    if (rel.type === '拱三会' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        if (zhi1 && zhi2) {
          const gongSanhui = isDizhiGongSanhui(zhi1, zhi2)
          if (gongSanhui.isGongSanhui) {
            if (gongSanhui.huahua) {
              return `拱会${gongSanhui.huahua}局`
            }
            return '拱三会'
          }
        }
      }
      return '拱三会'
    }
    
    // 地支暗合局（暗三合）- 显示暗合局+化气
    if (rel.type === '暗合局' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        const ganlist = props.pillars.map(p => p.gan).filter((gan): gan is string => !!gan)
        if (zhi1 && zhi2) {
          const anheJu = isDizhiAnheJu(zhi1, zhi2, ganlist)
          if (anheJu.isAnheJu && anheJu.huahua) {
            return `暗合${anheJu.huahua}局`
          }
        }
      }
      return '暗合局'
    }
    
    // 地支暗三会局 - 显示暗三会局+化气
    if (rel.type === '暗三会局' && rel.positions && rel.positions.length === 2) {
      const pos1 = rel.positions[0]
      const pos2 = rel.positions[1]
      if (pos1 !== undefined && pos2 !== undefined) {
        const zhi1 = props.pillars[pos1]?.zhi
        const zhi2 = props.pillars[pos2]?.zhi
        const ganlist = props.pillars.map(p => p.gan).filter((gan): gan is string => !!gan)
        if (zhi1 && zhi2) {
          const anSanhui = isDizhiAnSanhui(zhi1, zhi2, ganlist)
          if (anSanhui.isAnSanhui) {
            return '暗三会'
          }
        }
      }
      return '暗三会'
    }
    
    // 暗合 - 显示完整两个字
    if (rel.type === '暗合') {
      return '暗合'
    }
    
    // 其他关系类型使用完整显示
    const charMap: Record<string, string> = {
      '相冲': '相冲',
      '相刑': '相刑',
      '相破': '相破',
      '相害': '相害'
    }
    
    return charMap[rel.type] || rel.type
  }
  
  // 关系类型转单字（用于圆圈显示，保持简短）
  const getRelationSingleChar = (type: string): string => {
    const charMap: Record<string, string> = {
      '相冲': '冲',
      '五合': '合',
      '六合': '合',
      '三合': '合',
      '三会': '会',
      '暗合': '合',
      '相刑': '刑',
      '相破': '破',
      '相害': '害',
      '半合': '合',
      '拱三会': '会'
    }
    
    // 处理相克的情况（如"甲克乙"）
    if (type.includes('克')) {
      return '克'
    }
    
    return charMap[type] || type.charAt(type.length - 1)
  }
  
  // 判断是否是连接线起点
  const isLineStart = (rel: Relation, colIndex: number): boolean => {
    if (!rel.positions || rel.positions.length < 2) return false
    const sorted = [...rel.positions].sort((a, b) => a - b)
    return colIndex === sorted[0]
  }
  
  // 判断是否是连接线终点
  const isLineEnd = (rel: Relation, colIndex: number): boolean => {
    if (!rel.positions || rel.positions.length < 2) return false
    const sorted = [...rel.positions].sort((a, b) => a - b)
    return colIndex === sorted[sorted.length - 1]
  }
  
  // 获取天干关系的起点天干
  const getTianganStartChar = (rel: Relation): string => {
    if (!rel.positions || rel.positions.length < 2) return ''
    const sorted = [...rel.positions].sort((a, b) => a - b)
    const start = sorted[0]
    if (start === undefined) return ''
    return props.pillars[start]?.gan || ''
  }
  
  // 获取天干关系的终点天干
  const getTianganEndChar = (rel: Relation): string => {
    if (!rel.positions || rel.positions.length < 2) return ''
    const sorted = [...rel.positions].sort((a, b) => a - b)
    const end = sorted[sorted.length - 1]
    if (end === undefined) return ''
    return props.pillars[end]?.gan || ''
  }
  
  // 获取地支关系的起点地支
  const getDizhiStartChar = (rel: Relation): string => {
    if (!rel.positions || rel.positions.length < 2) return ''
    const sorted = [...rel.positions].sort((a, b) => a - b)
    const start = sorted[0]
    if (start === undefined) return ''
    return props.pillars[start]?.zhi || ''
  }
  
  // 获取地支关系的终点地支
  const getDizhiEndChar = (rel: Relation): string => {
    if (!rel.positions || rel.positions.length < 2) return ''
    const sorted = [...rel.positions].sort((a, b) => a - b)
    const end = sorted[sorted.length - 1]
    if (end === undefined) return ''
    return props.pillars[end]?.zhi || ''
  }
  
  // 计算天干关系
  const tianganRelations = computed<Relation[]>(() => {
    const relations: Relation[] = []
    const handled = new Set<string>()
    
    for (let i = 0; i < props.pillars.length; i++) {
      for (let j = i + 1; j < props.pillars.length; j++) {
        const pillar1 = props.pillars[i]
        const pillar2 = props.pillars[j]
        if (!pillar1 || !pillar2) continue
        
        const gan1 = pillar1.gan
        const gan2 = pillar2.gan
        const key = `${gan1}-${gan2}`
        const relationTypes: string[] = []
        
        // 检测所有可能的关系（允许同时存在多种关系）
        if (isTianganChong(gan1, gan2)) {
          relationTypes.push('相冲')
        }
        if (isTianganHe(gan1, gan2)) {
          relationTypes.push('五合')
        }
        // 先检查特定的天干相克关系
        if (isTianganKe(gan1, gan2)) {
          relationTypes.push(`${gan1}克${gan2}`)
        } else if (isTianganKe(gan2, gan1)) {
          relationTypes.push(`${gan2}克${gan1}`)
        } else {
          // 如果没有特定的天干相克，检查五行相克关系
          const gan1Wx = GANZHI_WUXING[gan1]
          const gan2Wx = GANZHI_WUXING[gan2]
          if (gan1Wx && gan2Wx) {
            // 五行相克关系映射
            const WUXING_KE: Record<string, string[]> = {
              '木': ['土'],
              '火': ['金'],
              '土': ['水'],
              '金': ['木'],
              '水': ['火']
            }
            if (WUXING_KE[gan1Wx]?.includes(gan2Wx)) {
              relationTypes.push(`${gan1}克${gan2}`)
            } else if (WUXING_KE[gan2Wx]?.includes(gan1Wx)) {
              relationTypes.push(`${gan2}克${gan1}`)
            }
          }
        }
        
        // 添加所有检测到的关系
        relationTypes.forEach((relType) => {
          const uniqueKey = `${key}-${relType}`
          if (!handled.has(uniqueKey)) {
            relations.push({ pair: `${gan1}${gan2}`, type: relType, positions: [i, j] })
            handled.add(uniqueKey)
          }
        })
      }
    }
    
    return relations
  })
  
  // 计算地支关系
  const dizhiRelations = computed<Relation[]>(() => {
    const relations: Relation[] = []
    const handled = new Set<string>()
    const zhilist = props.pillars.map(p => p.zhi)
    const ganlist = props.pillars.map(p => p.gan).filter((gan): gan is string => !!gan)
    
    // 两两地支关系（按优先级顺序检测，但需要检测所有关系类型）
    for (let i = 0; i < zhilist.length; i++) {
      for (let j = i + 1; j < zhilist.length; j++) {
        const zhi1 = zhilist[i]
        const zhi2 = zhilist[j]
        if (!zhi1 || !zhi2) continue
        
        const key = `${zhi1}-${zhi2}`
        const relationTypes: string[] = []
        
        // 检测所有可能的关系（按优先级，允许同时存在多种关系）
        // 先检测半合（因为半合是两个地支，需要优先检测，避免被三合覆盖）
        const banhe = isDizhiBanhe(zhi1, zhi2)
        if (banhe.isBanhe) {
          relationTypes.push('半合')
        }
        
        // 检测暗合局（暗三合）- 需要天干配合，优先检测
        const anheJu = isDizhiAnheJu(zhi1, zhi2, ganlist)
        if (anheJu.isAnheJu) {
          relationTypes.push('暗合局')
        }
        
        // 检测暗三会局 - 需要天干配合，优先检测
        const anSanhui = isDizhiAnSanhui(zhi1, zhi2, ganlist)
        if (anSanhui.isAnSanhui) {
          relationTypes.push('暗三会局')
        }
        
        // 检测拱合局（拱三合）- 如果暗合局不满足，才检测拱合
        if (!anheJu.isAnheJu) {
          const gonghe = isDizhiGonghe(zhi1, zhi2)
          if (gonghe.isGonghe) {
            relationTypes.push('拱合')
          }
        }
        
        // 检测拱三会（三会局缺少中间地支）- 暗三会局和拱三会可以同时显示
        const gongSanhui = isDizhiGongSanhui(zhi1, zhi2)
        if (gongSanhui.isGongSanhui) {
          relationTypes.push('拱三会')
        }
        
        if (isDizhiLiuhe(zhi1, zhi2)) {
          relationTypes.push('六合')
        }
        if (isDizhiChong(zhi1, zhi2)) {
          relationTypes.push('相冲')
        }
        if (isDizhiPo(zhi1, zhi2)) {
          relationTypes.push('相破')
        }
        if (isDizhiHai(zhi1, zhi2)) {
          relationTypes.push('相害')
        }
        if (isDizhiAnhe(zhi1, zhi2)) {
          relationTypes.push('暗合')
        }
        // 相刑检测（包括自刑：辰辰、午午、酉酉、亥亥）
        if (isDizhiXing(zhi1, zhi2)) {
          relationTypes.push('相刑')
        }
        
        // 添加所有检测到的关系（不再使用 else if，允许一个地支对存在多种关系）
        relationTypes.forEach((relType) => {
          const uniqueKey = `${key}-${relType}`
          if (!handled.has(uniqueKey)) {
            relations.push({ pair: `${zhi1}${zhi2}`, type: relType, positions: [i, j] })
            handled.add(uniqueKey)
          }
        })
      }
    }
    
    // 三合、三会关系
    for (let i = 0; i < zhilist.length; i++) {
      for (let j = i + 1; j < zhilist.length; j++) {
        for (let k = j + 1; k < zhilist.length; k++) {
          const zhi1 = zhilist[i]
          const zhi2 = zhilist[j]
          const zhi3 = zhilist[k]
          if (!zhi1 || !zhi2 || !zhi3) continue
          
          const key = [zhi1, zhi2, zhi3].sort().join('-')
          
          if (handled.has(key)) continue
          
          if (isDizhiSanhe(zhi1, zhi2, zhi3)) {
            relations.push({ pair: `${zhi1}${zhi2}${zhi3}`, type: '三合', positions: [i, j, k] })
            handled.add(key)
          } else if (isDizhiSanhui(zhi1, zhi2, zhi3)) {
            relations.push({ pair: `${zhi1}${zhi2}${zhi3}`, type: '三会', positions: [i, j, k] })
            handled.add(key)
          }
        }
      }
    }
    
    // 四地支合土局（丑_辰_未_戌合土局）
    if (zhilist.length === 4) {
      const zhi1 = zhilist[0]
      const zhi2 = zhilist[1]
      const zhi3 = zhilist[2]
      const zhi4 = zhilist[3]
      if (zhi1 && zhi2 && zhi3 && zhi4) {
        if (isDizhiSiheTu(zhi1, zhi2, zhi3, zhi4)) {
          const key = [zhi1, zhi2, zhi3, zhi4].sort().join('-')
          if (!handled.has(key)) {
            relations.push({ pair: `${zhi1}${zhi2}${zhi3}${zhi4}`, type: '四合土局', positions: [0, 1, 2, 3] })
            handled.add(key)
          }
        }
      }
    }
    
    return relations
  })
  
  // 分离单柱关系
  const singlePillarRelations = computed<Relation[]>(() => {
    return pillarRelations.value.filter(r => r.positions && r.positions.length === 1)
  })
  
  // 获取单个柱的关系
  const getSinglePillarRelations = (index: number): Relation[] => {
    return singlePillarRelations.value.filter(r => r.positions?.includes(index))
  }
  
  // 计算整柱关系
  const pillarRelations = computed<Relation[]>(() => {
    const relations: Relation[] = []
    const handled = new Set<string>()
    
    // 单柱关系（盖头、截脚）
    props.pillars.forEach((pillar, index) => {
      if (isGaitou(pillar.gan, pillar.zhi)) {
        relations.push({ 
          pair: `${pillar.gan}${pillar.zhi}`, 
          type: '盖头',
          positions: [index]
        })
      }
      if (isJiejiao(pillar.gan, pillar.zhi)) {
        relations.push({ 
          pair: `${pillar.gan}${pillar.zhi}`, 
          type: '截脚',
          positions: [index]
        })
      }
    })
    
    return relations
  })
  
  // 判断天干关系在该列是否有位置
  const getTianganRelationPosition = (rel: Relation, colIndex: number): boolean => {
    return rel.positions?.includes(colIndex) ?? false
  }
  
  // 判断是否绘制天干关系横线起点
  const getTianganRelationLineStart = (rel: Relation, colIndex: number): boolean => {
    if (!rel.positions || rel.positions.length < 2) return false
    const sorted = [...rel.positions].sort((a, b) => a - b)
    return colIndex === sorted[0]
  }
  
  // 动态计算连接线宽度和字体大小
  const gridRef = ref<HTMLElement | null>(null)
  const topLinesRef = ref<HTMLElement | null>(null)
  const bottomLinesRef = ref<HTMLElement | null>(null)
  const cellWidth = ref(0) // 单元格实际宽度（像素）
  const fontSize = ref(28) // 动态字体大小
  const headerFontSize = ref(13) // 表头字体大小
  const gap = 6 // CSS gap 值
  
  // 引导图层显示状态
  const showTopGuide = ref(true)
  const showBottomGuide = ref(true)
  const topGuideHiding = ref(false)
  const bottomGuideHiding = ref(false)
  
  // 触摸相关状态
  const topTouchStartX = ref(0)
  const bottomTouchStartX = ref(0)
  
  // 计算单元格实际宽度和字体大小
  const calculateCellWidth = () => {
    if (!gridRef.value) return
    const gridWidth = gridRef.value.offsetWidth
    const totalColumns = props.pillars.length
    const gapTotal = (totalColumns - 1) * gap
    // 单元格宽度 = (网格宽度 - gap总宽度) / 总列数
    cellWidth.value = (gridWidth - gapTotal) / totalColumns
    
    // 根据单元格宽度动态计算字体大小
    // 最小字体：20px，最大字体：28px（限制最大字体）
    // 当单元格宽度小于 40px 时，字体按比例缩小
    const minFontSize = 20
    const maxFontSize = 28
    const minCellWidth = 30
    const maxCellWidth = 100
    
    if (cellWidth.value <= minCellWidth) {
      fontSize.value = minFontSize
    } else if (cellWidth.value >= maxCellWidth) {
      fontSize.value = maxFontSize
    } else {
      // 线性插值
      const ratio = (cellWidth.value - minCellWidth) / (maxCellWidth - minCellWidth)
      fontSize.value = Math.round(minFontSize + (maxFontSize - minFontSize) * ratio)
    }
    
    // 表头字体大小：约为数据字体的 45%
    headerFontSize.value = Math.max(11, Math.round(fontSize.value * 0.45))
  }
  
  // 隐藏顶部引导图层
  const hideTopGuide = () => {
    if (topGuideHiding.value) return
    topGuideHiding.value = true
    setTimeout(() => {
      showTopGuide.value = false
    }, 300) // 淡出动画时长
  }
  
  // 隐藏底部引导图层
  const hideBottomGuide = () => {
    if (bottomGuideHiding.value) return
    bottomGuideHiding.value = true
    setTimeout(() => {
      showBottomGuide.value = false
    }, 300) // 淡出动画时长
  }
  
  // 顶部滚动处理
  const handleTopScroll = (e: Event) => {
    syncScroll(e)
    hideTopGuide()
  }
  
  // 底部滚动处理
  const handleBottomScroll = (e: Event) => {
    syncScroll(e)
    hideBottomGuide()
  }
  
  // 顶部触摸开始
  const handleTopTouchStart = (e: TouchEvent) => {
    const touch = e.touches[0]
    if (touch) {
      topTouchStartX.value = touch.clientX
    }
  }
  
  // 顶部触摸移动
  const handleTopTouchMove = (e: TouchEvent) => {
    const touch = e.touches[0]
    if (touch && topTouchStartX.value !== 0) {
      const deltaX = Math.abs(touch.clientX - topTouchStartX.value)
      if (deltaX > 10) {
        hideTopGuide()
      }
    }
  }
  
  // 底部触摸开始
  const handleBottomTouchStart = (e: TouchEvent) => {
    const touch = e.touches[0]
    if (touch) {
      bottomTouchStartX.value = touch.clientX
    }
  }
  
  // 底部触摸移动
  const handleBottomTouchMove = (e: TouchEvent) => {
    const touch = e.touches[0]
    if (touch && bottomTouchStartX.value !== 0) {
      const deltaX = Math.abs(touch.clientX - bottomTouchStartX.value)
      if (deltaX > 10) {
        hideBottomGuide()
      }
    }
  }
  
  // 同步滚动（顶部和底部连接线区域同步滚动）
  const syncScroll = (e: Event) => {
    const target = e.target as HTMLElement
    const scrollLeft = target.scrollLeft
    
    if (topLinesRef.value && target !== topLinesRef.value) {
      topLinesRef.value.scrollLeft = scrollLeft
    }
    if (bottomLinesRef.value && target !== bottomLinesRef.value) {
      bottomLinesRef.value.scrollLeft = scrollLeft
    }
  }
  
  // 监听窗口大小变化和关系变化，重新计算宽度
  onMounted(() => {
    nextTick(() => {
      calculateCellWidth()
      window.addEventListener('resize', calculateCellWidth)
    })
  })
  
  // 清理事件监听器
  onBeforeUnmount(() => {
    window.removeEventListener('resize', calculateCellWidth)
  })
  
  // 监听 pillars 变化，重新计算
  watch(() => props.pillars.length, () => {
    nextTick(() => {
      calculateCellWidth()
    })
  })
  
  // 监听 relations 变化，重新计算宽度（因为可能影响 DOM 尺寸）
  watch([tianganRelations, dizhiRelations], () => {
    nextTick(() => {
      calculateCellWidth()
    })
  }, { deep: true })
  
  // 获取天干关系横线样式 - 动态计算位置和长度
  const getTianganLineStyle = (rel: Relation, colIndex: number) => {
    if (!rel.positions || rel.positions.length < 2) return {}
    const sorted = [...rel.positions].sort((a, b) => a - b)
    const start = sorted[0]
    const end = sorted[sorted.length - 1]
    if (end === undefined || start === undefined) return {}
    
    if (colIndex !== start) return {}
    
    const span = end - start
    
    // 动态计算宽度（像素）
    // 从起点单元格中心到终点单元格中心：
    // = 起点单元格右半部分（50% * cellWidth）
    //   + 中间完整单元格（(span - 1) * cellWidth）
    //   + gap（span * gap）
    //   + 终点单元格左半部分（50% * cellWidth）
    // = span * cellWidth + span * gap
    
    if (cellWidth.value === 0) {
      // 如果还未计算，返回一个默认值
      return {
        left: '50%',
        width: `${span * 100}%`, // 临时值
      }
    }
    
    const width = span * cellWidth.value + span * gap
    
    return {
      left: '50%',
      width: `${width}px`,
    }
  }
  
  // 判断地支关系在该列是否有位置
  const getDizhiRelationPosition = (rel: Relation, colIndex: number): boolean => {
    return rel.positions?.includes(colIndex) ?? false
  }
  
  // 判断是否绘制地支关系横线起点
  const getDizhiRelationLineStart = (rel: Relation, colIndex: number): boolean => {
    if (!rel.positions || rel.positions.length < 2) return false
    const sorted = [...rel.positions].sort((a, b) => a - b)
    return colIndex === sorted[0]
  }
  
  // 获取地支关系横线样式 - 动态计算位置和长度
  const getDizhiLineStyle = (rel: Relation, colIndex: number) => {
    if (!rel.positions || rel.positions.length < 2) return {}
    const sorted = [...rel.positions].sort((a, b) => a - b)
    const start = sorted[0]
    const end = sorted[sorted.length - 1]
    if (end === undefined || start === undefined) return {}
    
    if (colIndex !== start) return {}
    
    const span = end - start
    
    if (cellWidth.value === 0) {
      return {
        left: '50%',
        width: `${span * 100}%`,
      }
    }
    
    const width = span * cellWidth.value + span * gap
    
    return {
      left: '50%',
      width: `${width}px`,
    }
  }
  </script>
  
  <style scoped>
    .ganzhi-relations {
      padding: 8px;
      background: #fff;
      width: 100%;
      max-width: 100%;
      box-sizing: border-box;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }
    
    /* 顶部连接线区域（可滚动） */
    .relation-lines-top {
      width: 100%;
      overflow-x: scroll;
      height: 200px;
      position: relative;
      flex-shrink: 0;
      -webkit-overflow-scrolling: touch;
      
      /* 显示滚动条（覆盖全局隐藏设置） */
      scrollbar-width: thin;
      scrollbar-color: rgba(148, 163, 184, 0.5) rgba(241, 245, 249, 0.3);
    }
    
    /* 顶部滚动条样式 - Chrome/Safari/Opera */
    .relation-lines-top::-webkit-scrollbar {
      display: block;
      height: 8px;
    }
    
    .relation-lines-top::-webkit-scrollbar-track {
      background: rgba(241, 245, 249, 0.3);
      border-radius: 4px;
    }
    
    .relation-lines-top::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.5);
      border-radius: 4px;
      transition: background 0.2s ease;
    }
    
    .relation-lines-top::-webkit-scrollbar-thumb:hover {
      background: rgba(148, 163, 184, 0.7);
    }
    
    .relation-grid-top {
      display: grid;
      grid-template-columns: repeat(var(--pillar-count, 4), 1fr);
      gap: 6px;
      width: 100%;
      box-sizing: border-box;
      overflow: visible;
      padding-top: 20px;
      padding-bottom: 20px;
    }
    
    /* 中间内容区域（固定，不滚动） */
    .relation-content-fixed {
      display: grid;
      grid-template-columns: repeat(var(--pillar-count, 4), 1fr);
      gap: 6px;
      width: 100%;
      box-sizing: border-box;
      overflow: visible;
      flex-shrink: 0;
    }
    
    /* 底部连接线区域（可滚动） */
    .relation-lines-bottom {
      width: 100%;
      overflow-x: scroll;
      height: 200px;
      position: relative;
      flex-shrink: 0;
      -webkit-overflow-scrolling: touch;
      
      /* 显示滚动条（覆盖全局隐藏设置） */
      scrollbar-width: thin;
      scrollbar-color: rgba(148, 163, 184, 0.5) rgba(241, 245, 249, 0.3);
    }
    
    /* 底部滚动条样式 - Chrome/Safari/Opera */
    .relation-lines-bottom::-webkit-scrollbar {
      display: block;
      height: 8px;
    }
    
    .relation-lines-bottom::-webkit-scrollbar-track {
      background: rgba(241, 245, 249, 0.3);
      border-radius: 4px;
    }
    
    .relation-lines-bottom::-webkit-scrollbar-thumb {
      background: rgba(148, 163, 184, 0.5);
      border-radius: 4px;
      transition: background 0.2s ease;
    }
    
    .relation-lines-bottom::-webkit-scrollbar-thumb:hover {
      background: rgba(148, 163, 184, 0.7);
    }
    
    .relation-grid-bottom {
      display: grid;
      grid-template-columns: repeat(var(--pillar-count, 4), 1fr);
      gap: 6px;
      width: 100%;
      box-sizing: border-box;
      overflow: visible;
      padding-top: 20px;
      padding-bottom: 20px;
    }
    
    .grid-header {
      padding: 2px 0;
      text-align: center;
      font-size: var(--header-font-size, 13px);
      font-weight: 500;
      color: #666;
      background: transparent;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    
    .data-cell {
      text-align: center;
      font-size: var(--font-size, 28px);
      /* 限制最大字体 */
      font-weight: 700;
      background: transparent;
      line-height: 1.2;
      word-break: keep-all;
      white-space: nowrap;
      height: 45px;
      /* 固定高度，稍微增大以容纳更大字体 */
      display: flex;
      align-items: center;
      justify-content: center;
      box-sizing: border-box;
    }
    
    .gan-cell {
      margin-bottom: 0;
    }
    
    .zhi-cell {
      margin-bottom: 0;
    }
    
    .relation-row {
      display: contents;
    }
    
    .relation-cell {
      position: relative;
      padding: 15px 4px;
      text-align: center;
      background: transparent;
      height: 50px;
      /* 固定高度 */
      overflow: visible;
      box-sizing: border-box;
    }
    
    .relation-line-container {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      pointer-events: none;
      z-index: 1;
      /* 容器定位和宽度由动态样式决定 */
    }
    
    .relation-line-horizontal {
      position: relative;
      width: 100%;
      height: 1px;
      background: #ccc;
      pointer-events: none;
    }
    
    .relation-dot {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 6px;
      height: 6px;
      border-radius: 50%;
      background: #999;
      z-index: 2;
      border: 1px solid #fff;
    }
    
    .relation-char-badge {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: calc(var(--font-size, 28px) * 0.85);
      height: calc(var(--font-size, 28px) * 0.85);
      min-width: 22px;
      min-height: 22px;
      max-width: 28px;
      max-height: 28px;
      border-radius: 50%;
      background: #fff;
      border: 1px solid #ccc;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: calc(var(--font-size, 28px) * 0.46);
      font-weight: 600;
      color: #ccc;
      z-index: 3;
      line-height: 1;
    }
    
    .relation-label-on-line {
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      font-size: clamp(11px, calc(var(--font-size, 28px) * 0.36), 14px);
      color: #ccc;
      font-weight: 400;
      white-space: nowrap;
      background: transparent;
      padding: 0 2px;
      z-index: 3;
      line-height: 1.2;
    }
    
    .label-above {
      top: -30px;
      transform: translateX(-50%);
    }
    
    .label-below {
      top: auto;
      bottom: -12px;
      transform: translateX(-50%);
    }
    
    .pillar-single-cell {
      padding: 2px 4px;
      text-align: center;
      font-size: calc(var(--font-size, 28px) * 0.39);
      min-height: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 4px;
      flex-wrap: wrap;
      background: transparent;
      box-sizing: border-box;
    }
    
    .pillar-single-tag {
      display: inline-block;
      padding: 2px 4px;
      font-size: calc(var(--font-size, 28px) * 0.36);
      color: #333;
      font-weight: 400;
      background: transparent;
      white-space: nowrap;
      word-break: keep-all;
    }
    
    .no-relations {
      text-align: center;
      padding: 40px 20px;
      color: #999;
      font-size: 14px;
      background: transparent;
    }
    
    /* 引导图层 */
    .scroll-guide {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: 10;
      background: rgba(0, 0, 0, 0.1);
      backdrop-filter: blur(2px);
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      animation: fadeIn 0.3s ease-in;
      transition: opacity 0.3s ease-out;
      border-radius: 10px;
    }
    
    .scroll-guide-hiding {
      opacity: 0;
      pointer-events: none;
    }
    
    .scroll-guide-content {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 12px;
      animation: slideUpDown 2s ease-in-out infinite;
    }
    
    .scroll-guide-icon {
      width: 48px;
      height: 48px;
      color: #ffffff;
      display: flex;
      align-items: center;
      justify-content: center;
      animation: slideLeftRight 1.5s ease-in-out infinite;
    }
    
    .scroll-guide-icon svg {
      width: 100%;
      height: 100%;
    }
    
    .scroll-guide-text {
      font-size: 14px;
      color: #ffffff;
      font-weight: 500;
      text-align: center;
      padding: 8px 16px;
      background: rgba(255, 255, 255, 0.2);
      border-radius: 20px;
      white-space: nowrap;
    }
    
    /* 淡入动画 */
    @keyframes fadeIn {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    
    /* 上下滑动动画（提示用户可以滑动） */
    @keyframes slideUpDown {
      0%, 100% {
        transform: translateY(0);
      }
      50% {
        transform: translateY(-10px);
      }
    }
    
    /* 左右滑动动画（提示横向滑动） */
    @keyframes slideLeftRight {
      0%, 100% {
        transform: translateX(0);
      }
      25% {
        transform: translateX(-8px);
      }
      75% {
        transform: translateX(8px);
      }
    }
  </style>